home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / unix / regexp.1 < prev    next >
Text File  |  1988-12-06  |  20KB  |  748 lines

  1. Path: xanth!ames!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i085:  regexp - regular-expression routines, Part01/02
  5. Message-ID: <10484@swan.ulowell.edu>
  6. Date: 5 Dec 88 22:05:51 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 737
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: grwalter@watcgl.waterloo.edu
  12. Posting-number: Volume 2, Issue 85
  13. Archive-name: unix/regexp.1
  14.  
  15. This is a reimplementation of the Unix V8 regexp(3) package.  It gives
  16. C programs the ability to use egrep-style regular expressions, and
  17. does it in a much cleaner fashion than the analogous routines in SysV.
  18.  
  19. [You need this to recompile stevie.  ..Bob]
  20.  
  21. #    This is a shell archive.
  22. #    Remove everything above and including the cut line.
  23. #    Then run the rest of the file through sh.
  24. #----cut here-----cut here-----cut here-----cut here----#
  25. #!/bin/sh
  26. # shar:    Shell Archiver
  27. #    Run the following text with /bin/sh to create:
  28. #    MAKE
  29. #    Makefile
  30. #    README
  31. #    tests
  32. #    timer.c
  33. #    try.c
  34. # This archive created: Mon Nov 28 19:50:49 1988
  35. cat << \SHAR_EOF > MAKE
  36. lc -M -Rregexp.lib regexp.c regsub.c regerror.c
  37. SHAR_EOF
  38. cat << \SHAR_EOF > Makefile
  39. # Things you might want to put in ENV and LENV:
  40. # -Dvoid=int        compilers that don't do void
  41. # -DCHARBITS=0377    compilers that don't do unsigned char
  42. # -DSTATIC=extern    compilers that don't like "static foo();" as forward decl
  43. # -DSTRCSPN        library does not have strcspn()
  44. # -Dstrchr=index    library does not have strchr()
  45. # -DERRAVAIL        have utzoo-compatible error() function and friends
  46. ENV=-DSTRCSPN
  47. LENV=-DSTRCSPN
  48.  
  49. # Things you might want to put in TEST:
  50. # -DDEBUG        debugging hooks
  51. # -I.            regexp.h from current directory, not /usr/include
  52. TEST=-I.
  53.  
  54. # Things you might want to put in PROF:
  55. # -Dstatic='/* */'    make everything global so profiler can see it.
  56. # -p            profiler
  57. PROF=
  58.  
  59. CFLAGS=-O $(ENV) $(TEST) $(PROF)
  60. LINTFLAGS=$(LENV) $(TEST) -ha
  61. LDFLAGS=-i
  62.  
  63. OBJ=regexp.o regsub.o
  64. LSRC=regexp.c regsub.c regerror.c
  65. DTR=README dMakefile regexp.3 regexp.h regexp.c regsub.c regerror.c \
  66.     regmagic.h try.c timer.c tests
  67. DEST = ..
  68.  
  69. try:    try.o $(OBJ)
  70.     cc $(LDFLAGS) try.o $(OBJ) -o try
  71.  
  72. # Making timer will probably require putting stuff in $(PROF) and then
  73. # recompiling everything; the following is just the final stage.
  74. timer:    timer.o $(OBJ)
  75.     cc $(LDFLAGS) $(PROF) timer.o $(OBJ) -o timer
  76.  
  77. timer.o:    timer.c timer.t.h
  78.  
  79. timer.t.h:    tests
  80.     sed 's/    /","/g;s/\\/&&/g;s/.*/{"&"},/' tests >timer.t.h
  81.  
  82. # Regression test.
  83. r:    try tests
  84.     @echo 'No news is good news...'
  85.     try <tests
  86.  
  87. lint:    timer.t.h
  88.     @echo 'Complaints about multiply-declared regerror() are legit.'
  89.     lint $(LINTFLAGS) $(LSRC) try.c
  90.     lint $(LINTFLAGS) $(LSRC) timer.c
  91.  
  92. regexp.o:    regexp.c regexp.h regmagic.h
  93. regsub.o:    regsub.c regexp.h regmagic.h
  94.  
  95. clean:
  96.     rm -f *.o *.out core mon.out timer.t.h dMakefile dtr try timer
  97.  
  98. dtr:    r makedtr $(DTR)
  99.     makedtr $(DTR) >dtr
  100.  
  101. dMakefile:    Makefile
  102.     sed '/^L*ENV=/s/ *-DERRAVAIL//' Makefile >dMakefile
  103.  
  104. mv:    $(OBJ) regerror.o
  105.     mv $(OBJ) regerror.o $(DEST)
  106. SHAR_EOF
  107. cat << \SHAR_EOF > README
  108. This is a nearly-public-domain reimplementation of the V8 regexp(3) package.
  109. It gives C programs the ability to use egrep-style regular expressions, and
  110. does it in a much cleaner fashion than the analogous routines in SysV.
  111.  
  112.     Copyright (c) 1986 by University of Toronto.
  113.     Written by Henry Spencer.  Not derived from licensed software.
  114.  
  115.     Permission is granted to anyone to use this software for any
  116.     purpose on any computer system, and to redistribute it freely,
  117.     subject to the following restrictions:
  118.  
  119.     1. The author is not responsible for the consequences of use of
  120.         this software, no matter how awful, even if they arise
  121.         from defects in it.
  122.  
  123.     2. The origin of this software must not be misrepresented, either
  124.         by explicit claim or by omission.
  125.  
  126.     3. Altered versions must be plainly marked as such, and must not
  127.         be misrepresented as being the original software.
  128.  
  129. Barring a couple of small items in the BUGS list, this implementation is
  130. believed 100% compatible with V8.  It should even be binary-compatible,
  131. sort of, since the only fields in a "struct regexp" that other people have
  132. any business touching are declared in exactly the same way at the same
  133. location in the struct (the beginning).
  134.  
  135. This implementation is *NOT* AT&T/Bell code, and is not derived from licensed
  136. software.  Even though U of T is a V8 licensee.  This software is based on
  137. a V8 manual page sent to me by Dennis Ritchie (the manual page enclosed
  138. here is a complete rewrite and hence is not covered by AT&T copyright).
  139. The software was nearly complete at the time of arrival of our V8 tape.
  140. I haven't even looked at V8 yet, although a friend elsewhere at U of T has
  141. been kind enough to run a few test programs using the V8 regexp(3) to resolve
  142. a few fine points.  I admit to some familiarity with regular-expression
  143. implementations of the past, but the only one that this code traces any
  144. ancestry to is the one published in Kernighan & Plauger (from which this
  145. one draws ideas but not code).
  146.  
  147. Simplistically:  put this stuff into a source directory, copy regexp.h into
  148. /usr/include, inspect Makefile for compilation options that need changing
  149. to suit your local environment, and then do "make r".  This compiles the
  150. regexp(3) functions, compiles a test program, and runs a large set of
  151. regression tests.  If there are no complaints, then put regexp.o, regsub.o,
  152. and regerror.o into your C library, and regexp.3 into your manual-pages
  153. directory.
  154.  
  155. Note that if you don't put regexp.h into /usr/include *before* compiling,
  156. you'll have to add "-I." to CFLAGS before compiling.
  157.  
  158. The files are:
  159.  
  160. Makefile    instructions to make everything
  161. regexp.3    manual page
  162. regexp.h    header file, for /usr/include
  163. regexp.c    source for regcomp() and regexec()
  164. regsub.c    source for regsub()
  165. regerror.c    source for default regerror()
  166. regmagic.h    internal header file
  167. try.c        source for test program
  168. timer.c        source for timing program
  169. tests        test list for try and timer
  170.  
  171. This implementation uses nondeterministic automata rather than the
  172. deterministic ones found in some other implementations, which makes it
  173. simpler, smaller, and faster at compiling regular expressions, but slower
  174. at executing them.  In theory, anyway.  This implementation does employ
  175. some special-case optimizations to make the simpler cases (which do make
  176. up the bulk of regular expressions actually used) run quickly.  In general,
  177. if you want blazing speed you're in the wrong place.  Replacing the insides
  178. of egrep with this stuff is probably a mistake; if you want your own egrep
  179. you're going to have to do a lot more work.  But if you want to use regular
  180. expressions a little bit in something else, you're in luck.  Note that many
  181. existing text editors use nondeterministic regular-expression implementations,
  182. so you're in good company.
  183.  
  184. This stuff should be pretty portable, given appropriate option settings.
  185. If your chars have less than 8 bits, you're going to have to change the
  186. internal representation of the automaton, although knowledge of the details
  187. of this is fairly localized.  There are no "reserved" char values except for
  188. NUL, and no special significance is attached to the top bit of chars.
  189. The string(3) functions are used a fair bit, on the grounds that they are
  190. probably faster than coding the operations in line.  Some attempts at code
  191. tuning have been made, but this is invariably a bit machine-specific.
  192. SHAR_EOF
  193. cat << \SHAR_EOF > tests
  194. abc    abc    y    &    abc
  195. abc    xbc    n    -    -
  196. abc    axc    n    -    -
  197. abc    abx    n    -    -
  198. abc    xabcy    y    &    abc
  199. abc    ababc    y    &    abc
  200. ab*c    abc    y    &    abc
  201. ab*bc    abc    y    &    abc
  202. ab*bc    abbc    y    &    abbc
  203. ab*bc    abbbbc    y    &    abbbbc
  204. ab+bc    abbc    y    &    abbc
  205. ab+bc    abc    n    -    -
  206. ab+bc    abq    n    -    -
  207. ab+bc    abbbbc    y    &    abbbbc
  208. ab?bc    abbc    y    &    abbc
  209. ab?bc    abc    y    &    abc
  210. ab?bc    abbbbc    n    -    -
  211. ab?c    abc    y    &    abc
  212. ^abc$    abc    y    &    abc
  213. ^abc$    abcc    n    -    -
  214. ^abc    abcc    y    &    abc
  215. ^abc$    aabc    n    -    -
  216. abc$    aabc    y    &    abc
  217. ^    abc    y    &    
  218. $    abc    y    &    
  219. a.c    abc    y    &    abc
  220. a.c    axc    y    &    axc
  221. a.*c    axyzc    y    &    axyzc
  222. a.*c    axyzd    n    -    -
  223. a[bc]d    abc    n    -    -
  224. a[bc]d    abd    y    &    abd
  225. a[b-d]e    abd    n    -    -
  226. a[b-d]e    ace    y    &    ace
  227. a[b-d]    aac    y    &    ac
  228. a[-b]    a-    y    &    a-
  229. a[b-]    a-    y    &    a-
  230. [k]    ab    n    -    -
  231. a[b-a]    -    c    -    -
  232. a[]b    -    c    -    -
  233. a[    -    c    -    -
  234. a]    a]    y    &    a]
  235. a[]]b    a]b    y    &    a]b
  236. a[^bc]d    aed    y    &    aed
  237. a[^bc]d    abd    n    -    -
  238. a[^-b]c    adc    y    &    adc
  239. a[^-b]c    a-c    n    -    -
  240. a[^]b]c    a]c    n    -    -
  241. a[^]b]c    adc    y    &    adc
  242. ab|cd    abc    y    &    ab
  243. ab|cd    abcd    y    &    ab
  244. ()ef    def    y    &-\1    ef-
  245. ()*    -    c    -    -
  246. *a    -    c    -    -
  247. ^*    -    c    -    -
  248. $*    -    c    -    -
  249. (*)b    -    c    -    -
  250. $b    b    n    -    -
  251. a\    -    c    -    -
  252. a\(b    a(b    y    &-\1    a(b-
  253. a\(*b    ab    y    &    ab
  254. a\(*b    a((b    y    &    a((b
  255. a\\b    a\b    y    &    a\b
  256. abc)    -    c    -    -
  257. (abc    -    c    -    -
  258. ((a))    abc    y    &-\1-\2    a-a-a
  259. (a)b(c)    abc    y    &-\1-\2    abc-a-c
  260. a+b+c    aabbabc    y    &    abc
  261. a**    -    c    -    -
  262. a*?    -    c    -    -
  263. (a*)*    -    c    -    -
  264. (a*)+    -    c    -    -
  265. (a|)*    -    c    -    -
  266. (a*|b)*    -    c    -    -
  267. (a+|b)*    ab    y    &-\1    ab-b
  268. (a+|b)+    ab    y    &-\1    ab-b
  269. (a+|b)?    ab    y    &-\1    a-a
  270. [^ab]*    cde    y    &    cde
  271. (^)*    -    c    -    -
  272. (ab|)*    -    c    -    -
  273. )(    -    c    -    -
  274.     abc    y    &    
  275. abc        n    -    -
  276. a*        y    &    
  277. abcd    abcd    y    &-\&-\\&    abcd-&-\abcd
  278. a(bc)d    abcd    y    \1-\\1-\\\1    bc-\1-\bc
  279. ([abc])*d    abbbcd    y    &-\1    abbbcd-c
  280. ([abc])*bcd    abcd    y    &-\1    abcd-a
  281. a|b|c|d|e    e    y    &    e
  282. (a|b|c|d|e)f    ef    y    &-\1    ef-e
  283. ((a*|b))*    -    c    -    -
  284. abcd*efg    abcdefg    y    &    abcdefg
  285. ab*    xabyabbbz    y    &    ab
  286. ab*    xayabbbz    y    &    a
  287. (ab|cd)e    abcde    y    &-\1    cde-cd
  288. [abhgefdc]ij    hij    y    &    hij
  289. ^(ab|cd)e    abcde    n    x\1y    xy
  290. (abc|)ef    abcdef    y    &-\1    ef-
  291. (a|b)c*d    abcd    y    &-\1    bcd-b
  292. (ab|ab*)bc    abc    y    &-\1    abc-a
  293. a([bc]*)c*    abc    y    &-\1    abc-bc
  294. a([bc]*)(c*d)    abcd    y    &-\1-\2    abcd-bc-d
  295. a([bc]+)(c*d)    abcd    y    &-\1-\2    abcd-bc-d
  296. a([bc]*)(c+d)    abcd    y    &-\1-\2    abcd-b-cd
  297. a[bcd]*dcdcde    adcdcde    y    &    adcdcde
  298. a[bcd]+dcdcde    adcdcde    n    -    -
  299. (ab|a)b*c    abc    y    &-\1    abc-ab
  300. ((a)(b)c)(d)    abcd    y    \1-\2-\3-\4    abc-a-b-d
  301. [ -~]*    abc    y    &    abc
  302. [ -~ -~]*    abc    y    &    abc
  303. [ -~ -~ -~]*    abc    y    &    abc
  304. [ -~ -~ -~ -~]*    abc    y    &    abc
  305. [ -~ -~ -~ -~ -~]*    abc    y    &    abc
  306. [ -~ -~ -~ -~ -~ -~]*    abc    y    &    abc
  307. [ -~ -~ -~ -~ -~ -~ -~]*    abc    y    &    abc
  308. [a-zA-Z_][a-zA-Z0-9_]*    alpha    y    &    alpha
  309. ^a(bc+|b[eh])g|.h$    abh    y    &-\1    bh-
  310. (bc+d$|ef*g.|h?i(j|k))    effgz    y    &-\1-\2    effgz-effgz-
  311. (bc+d$|ef*g.|h?i(j|k))    ij    y    &-\1-\2    ij-ij-j
  312. (bc+d$|ef*g.|h?i(j|k))    effg    n    -    -
  313. (bc+d$|ef*g.|h?i(j|k))    bcdd    n    -    -
  314. (bc+d$|ef*g.|h?i(j|k))    reffgz    y    &-\1-\2    effgz-effgz-
  315. ((((((((((a))))))))))    -    c    -    -
  316. (((((((((a)))))))))    a    y    &    a
  317. multiple words of text    uh-uh    n    -    -
  318. multiple words    multiple words, yeah    y    &    multiple words
  319. (.*)c(.*)    abcde    y    &-\1-\2    abcde-ab-de
  320. \((.*), (.*)\)    (a, b)    y    (\2, \1)    (b, a)
  321. SHAR_EOF
  322. cat << \SHAR_EOF > timer.c
  323. /*
  324.  * Simple timing program for regcomp(). 
  325.  *
  326.  * Copyright (c) 1986 by University of Toronto. Written by Henry Spencer.  Not
  327.  * derived from licensed software. 
  328.  *
  329.  * Permission is granted to anyone to use this software for any purpose on any
  330.  * computer system, and to redistribute it freely, subject to the following
  331.  * restrictions: 
  332.  *
  333.  * 1. The author is not responsible for the consequences of use of this
  334.  * software, no matter how awful, even if they arise from defects in it. 
  335.  *
  336.  * 2. The origin of this software must not be misrepresented, either by explicit
  337.  * claim or by omission. 
  338.  *
  339.  * 3. Altered versions must be plainly marked as such, and must not be
  340.  * misrepresented as being the original software. 
  341.  *
  342.  * Usage: timer ncomp nexec nsub or timer ncomp nexec nsub regexp string [
  343.  * answer [ sub ] ] 
  344.  *
  345.  * The second form is for timing repetitions of a single test case. The first
  346.  * form's test data is a compiled-in copy of the "tests" file. Ncomp, nexec,
  347.  * nsub are how many times to do each regcomp, regexec, and regsub.  The way
  348.  * to time an operation individually is to do something like "timer 1 50 1". 
  349.  */
  350. #include <stdio.h>
  351.  
  352. struct try {
  353.     char           *re, *str, *ans, *src, *dst;
  354. }               tests[] = {
  355. #include "timer.t.h"
  356.     {
  357.                     NULL, NULL, NULL, NULL, NULL
  358.     }
  359. };
  360.  
  361. #include <regexp.h>
  362.  
  363. int             errreport = 0;    /* Report errors via errseen? */
  364. char           *errseen = NULL;    /* Error message. */
  365.  
  366. char           *progname;
  367.  
  368. /* ARGSUSED */
  369. main(argc, argv)
  370.     int             argc;
  371.     char           *argv[];
  372. {
  373.     int             ncomp, nexec, nsub;
  374.     struct try      one;
  375.     char            dummy[512];
  376.  
  377.     if (argc < 4) {
  378.     ncomp = 1;
  379.     nexec = 1;
  380.     nsub = 1;
  381.     } else {
  382.     ncomp = atoi(argv[1]);
  383.     nexec = atoi(argv[2]);
  384.     nsub = atoi(argv[3]);
  385.     }
  386.  
  387.     progname = argv[0];
  388.     if (argc > 5) {
  389.     one.re = argv[4];
  390.     one.str = argv[5];
  391.     if (argc > 6)
  392.         one.ans = argv[6];
  393.     else
  394.         one.ans = "y";
  395.     if (argc > 7) {
  396.         one.src = argv[7];
  397.         one.dst = "xxx";
  398.     } else {
  399.         one.src = "x";
  400.         one.dst = "x";
  401.     }
  402.     errreport = 1;
  403.     try(one, ncomp, nexec, nsub);
  404.     } else
  405.     multiple(ncomp, nexec, nsub);
  406.     exit(0);
  407. }
  408.  
  409. void
  410. regerror(s)
  411.     char           *s;
  412. {
  413.     if (errreport)
  414.     errseen = s;
  415.     else
  416.     error(s, "");
  417. }
  418.  
  419. #ifndef ERRAVAIL
  420. error(s1, s2)
  421.     char           *s1;
  422.     char           *s2;
  423. {
  424.     fprintf(stderr, "regexp: ");
  425.     fprintf(stderr, s1, s2);
  426.     fprintf(stderr, "\n");
  427.     exit(1);
  428. }
  429. #endif
  430.  
  431. int             lineno = 0;
  432.  
  433. multiple(ncomp, nexec, nsub)
  434.     int             ncomp, nexec, nsub;
  435. {
  436.     register int    i;
  437.     extern char    *strchr();
  438.  
  439.     errreport = 1;
  440.     for (i = 0; tests[i].re != NULL; i++) {
  441.     lineno++;
  442.     try(tests[i], ncomp, nexec, nsub);
  443.     }
  444. }
  445.  
  446. try(fields, ncomp, nexec, nsub)
  447.     struct try      fields;
  448.     int             ncomp, nexec, nsub;
  449. {
  450.     regexp         *r;
  451.     char            dbuf[BUFSIZ];
  452.     register int    i;
  453.  
  454.     errseen = NULL;
  455.     r = regcomp(fields.re);
  456.     if (r == NULL) {
  457.     if (*fields.ans != 'c')
  458.         complain("regcomp failure in `%s'", fields.re);
  459.     return;
  460.     }
  461.     if (*fields.ans == 'c') {
  462.     complain("unexpected regcomp success in `%s'", fields.re);
  463.     free((char *) r);
  464.     return;
  465.     }
  466.     for (i = ncomp - 1; i > 0; i--) {
  467.     free((char *) r);
  468.     r = regcomp(fields.re);
  469.     }
  470.     if (!regexec(r, fields.str)) {
  471.     if (*fields.ans != 'n')
  472.         complain("regexec failure in `%s'", "");
  473.     free((char *) r);
  474.     return;
  475.     }
  476.     if (*fields.ans == 'n') {
  477.     complain("unexpected regexec success", "");
  478.     free((char *) r);
  479.     return;
  480.     }
  481.     for (i = nexec - 1; i > 0; i--)
  482.     (void) regexec(r, fields.str);
  483.     errseen = NULL;
  484.     for (i = nsub; i > 0; i--)
  485.     regsub(r, fields.src, dbuf);
  486.     if (errseen != NULL) {
  487.     complain("regsub complaint", "");
  488.     free((char *) r);
  489.     return;
  490.     }
  491.     if (strcmp(dbuf, fields.dst) != 0)
  492.     complain("regsub result `%s' wrong", dbuf);
  493.     free((char *) r);
  494. }
  495.  
  496. complain(s1, s2)
  497.     char           *s1;
  498.     char           *s2;
  499. {
  500.     fprintf(stderr, "try: %d: ", lineno);
  501.     fprintf(stderr, s1, s2);
  502.     fprintf(stderr, " (%s)\n", (errseen != NULL) ? errseen : "");
  503. }
  504. SHAR_EOF
  505. cat << \SHAR_EOF > try.c
  506. /*
  507.  * Simple test program for regexp(3) stuff.  Knows about debugging hooks. 
  508.  *
  509.  * Copyright (c) 1986 by University of Toronto. Written by Henry Spencer.  Not
  510.  * derived from licensed software. 
  511.  *
  512.  * Permission is granted to anyone to use this software for any purpose on any
  513.  * computer system, and to redistribute it freely, subject to the following
  514.  * restrictions: 
  515.  *
  516.  * 1. The author is not responsible for the consequences of use of this
  517.  * software, no matter how awful, even if they arise from defects in it. 
  518.  *
  519.  * 2. The origin of this software must not be misrepresented, either by explicit
  520.  * claim or by omission. 
  521.  *
  522.  * 3. Altered versions must be plainly marked as such, and must not be
  523.  * misrepresented as being the original software. 
  524.  *
  525.  * Usage: try re [string [output [-]]] The re is compiled and dumped, regexeced
  526.  * against the string, the result is applied to output using regsub().  The -
  527.  * triggers a running narrative from regexec().  Dumping and narrative don't
  528.  * happen unless DEBUG. 
  529.  *
  530.  * If there are no arguments, stdin is assumed to be a stream of lines with five
  531.  * fields:  a r.e., a string to match it against, a result code, a source
  532.  * string for regsub, and the proper result.  Result codes are 'c' for
  533.  * compile failure, 'y' for match success, 'n' for match failure. Field
  534.  * separator is tab. 
  535.  */
  536. #include <stdio.h>
  537. #include <regexp.h>
  538.  
  539. #ifdef ERRAVAIL
  540. char           *progname;
  541. extern char    *mkprogname();
  542. #endif
  543.  
  544. #ifdef DEBUG
  545. extern int      regnarrate;
  546. #endif
  547.  
  548. char            buf[BUFSIZ];
  549.  
  550. int             errreport = 0;    /* Report errors via errseen? */
  551. char           *errseen = NULL;    /* Error message. */
  552. int             status = 0;    /* Exit status. */
  553.  
  554. /* ARGSUSED */
  555. main(argc, argv)
  556.     int             argc;
  557.     char           *argv[];
  558. {
  559.     regexp         *r;
  560.     int             i;
  561.  
  562. #ifdef ERRAVAIL
  563.     progname = mkprogname(argv[0]);
  564. #endif
  565.  
  566.     if (argc == 1) {
  567.     multiple();
  568.     exit(status);
  569.     }
  570.     r = regcomp(argv[1]);
  571.     if (r == NULL)
  572.     error("regcomp failure", "");
  573. #ifdef DEBUG
  574.     regdump(r);
  575.     if (argc > 4)
  576.     regnarrate++;
  577. #endif
  578.     if (argc > 2) {
  579.     i = regexec(r, argv[2]);
  580.     printf("%d", i);
  581.     for (i = 1; i < NSUBEXP; i++)
  582.         if (r->startp[i] != NULL && r->endp[i] != NULL)
  583.         printf(" \\%d", i);
  584.     printf("\n");
  585.     }
  586.     if (argc > 3) {
  587.     regsub(r, argv[3], buf);
  588.     printf("%s\n", buf);
  589.     }
  590.     exit(status);
  591. }
  592.  
  593. void
  594. regerror(s)
  595.     char           *s;
  596. {
  597.     if (errreport)
  598.     errseen = s;
  599.     else
  600.     error(s, "");
  601. }
  602.  
  603. #ifndef ERRAVAIL
  604. error(s1, s2)
  605.     char           *s1;
  606.     char           *s2;
  607. {
  608.     fprintf(stderr, "regexp: ");
  609.     fprintf(stderr, s1, s2);
  610.     fprintf(stderr, "\n");
  611.     exit(1);
  612. }
  613. #endif
  614.  
  615. int             lineno;
  616.  
  617. regexp          badregexp;    /* Implicit init to 0. */
  618.  
  619. multiple()
  620. {
  621.     char            rbuf[BUFSIZ];
  622.     char           *field[5];
  623.     char           *scan;
  624.     int             i;
  625.     regexp         *r;
  626.     extern char    *strchr();
  627.  
  628.     errreport = 1;
  629.     lineno = 0;
  630.     while (fgets(rbuf, sizeof(rbuf), stdin) != NULL) {
  631.     rbuf[strlen(rbuf) - 1] = '\0';    /* Dispense with \n. */
  632.     lineno++;
  633.     scan = rbuf;
  634.     for (i = 0; i < 5; i++) {
  635.         field[i] = scan;
  636.         if (field[i] == NULL) {
  637.         complain("bad testfile format", "");
  638.         exit(1);
  639.         }
  640.         scan = strchr(scan, '\t');
  641.         if (scan != NULL)
  642.         *scan++ = '\0';
  643.     }
  644.     try(field);
  645.     }
  646.  
  647.     /* And finish up with some internal testing... */
  648.     lineno = 9990;
  649.     errseen = NULL;
  650.     if (regcomp((char *) NULL) != NULL || errseen == NULL)
  651.     complain("regcomp(NULL) doesn't complain", "");
  652.     lineno = 9991;
  653.     errseen = NULL;
  654.     if (regexec((regexp *) NULL, "foo") || errseen == NULL)
  655.     complain("regexec(NULL, ...) doesn't complain", "");
  656.     lineno = 9992;
  657.     r = regcomp("foo");
  658.     if (r == NULL) {
  659.     complain("regcomp(\"foo\") fails", "");
  660.     return;
  661.     }
  662.     lineno = 9993;
  663.     errseen = NULL;
  664.     if (regexec(r, (char *) NULL) || errseen == NULL)
  665.     complain("regexec(..., NULL) doesn't complain", "");
  666.     lineno = 9994;
  667.     errseen = NULL;
  668.     regsub((regexp *) NULL, "foo", rbuf);
  669.     if (errseen == NULL)
  670.     complain("regsub(NULL, ..., ...) doesn't complain", "");
  671.     lineno = 9995;
  672.     errseen = NULL;
  673.     regsub(r, (char *) NULL, rbuf);
  674.     if (errseen == NULL)
  675.     complain("regsub(..., NULL, ...) doesn't complain", "");
  676.     lineno = 9996;
  677.     errseen = NULL;
  678.     regsub(r, "foo", (char *) NULL);
  679.     if (errseen == NULL)
  680.     complain("regsub(..., ..., NULL) doesn't complain", "");
  681.     lineno = 9997;
  682.     errseen = NULL;
  683.     if (regexec(&badregexp, "foo") || errseen == NULL)
  684.     complain("regexec(nonsense, ...) doesn't complain", "");
  685.     lineno = 9998;
  686.     errseen = NULL;
  687.     regsub(&badregexp, "foo", rbuf);
  688.     if (errseen == NULL)
  689.     complain("regsub(nonsense, ..., ...) doesn't complain", "");
  690. }
  691.  
  692. try(fields)
  693.     char          **fields;
  694. {
  695.     regexp         *r;
  696.     char            dbuf[BUFSIZ];
  697.  
  698.     errseen = NULL;
  699.     r = regcomp(fields[0]);
  700.     if (r == NULL) {
  701.     if (*fields[2] != 'c')
  702.         complain("regcomp failure in `%s'", fields[0]);
  703.     return;
  704.     }
  705.     if (*fields[2] == 'c') {
  706.     complain("unexpected regcomp success in `%s'", fields[0]);
  707.     free((char *) r);
  708.     return;
  709.     }
  710.     if (!regexec(r, fields[1])) {
  711.     if (*fields[2] != 'n')
  712.         complain("regexec failure in `%s'", "");
  713.     free((char *) r);
  714.     return;
  715.     }
  716.     if (*fields[2] == 'n') {
  717.     complain("unexpected regexec success", "");
  718.     free((char *) r);
  719.     return;
  720.     }
  721.     errseen = NULL;
  722.     regsub(r, fields[3], dbuf);
  723.     if (errseen != NULL) {
  724.     complain("regsub complaint", "");
  725.     free((char *) r);
  726.     return;
  727.     }
  728.     if (strcmp(dbuf, fields[4]) != 0)
  729.     complain("regsub result `%s' wrong", dbuf);
  730.     free((char *) r);
  731. }
  732.  
  733. complain(s1, s2)
  734.     char           *s1;
  735.     char           *s2;
  736. {
  737.     fprintf(stderr, "try: %d: ", lineno);
  738.     fprintf(stderr, s1, s2);
  739.     fprintf(stderr, " (%s)\n", (errseen != NULL) ? errseen : "");
  740.     status = 1;
  741. }
  742. SHAR_EOF
  743. #    End of shell archive
  744. exit 0
  745. -- 
  746. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  747. Have five nice days.
  748.